package com.bjtime.designer

import android.graphics.*
import android.text.TextUtils
import com.bjtime.designer.attributes.QRCodeAttr
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.MultiFormatWriter
import com.google.zxing.WriterException
import com.google.zxing.common.BitMatrix
import com.google.zxing.oned.Code128Writer
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import java.util.*


class QRCode {

    constructor()


    companion object {
        /*生成二维码*/
        fun createQRCode(content: String, w: Int, h: Int, logo: Bitmap?, format : QRCodeAttr.QRTYPE): Bitmap? {
            if (TextUtils.isEmpty(content)) {
                return null
            }
            /*偏移量*/
            var offsetX = w / 2
            var offsetY = h / 2

            /*生成logo*/
            var logoBitmap: Bitmap? = null

            if (logo != null) {
                val matrix = Matrix()
                val scaleFactor = Math.min(
                    w * 1.0f / 5f / logo.width.toFloat(),
                    h * 1.0f / 5f / logo.height.toFloat()
                )
                matrix.postScale(scaleFactor, scaleFactor)
                logoBitmap = Bitmap.createBitmap(logo, 0, 0, logo.width, logo.height, matrix, true)
            }


            /*如果log不为null,重新计算偏移量*/
            var logoW = 0
            var logoH = 0
            if (logoBitmap != null) {
                logoW = logoBitmap.width
                logoH = logoBitmap.height
                offsetX = (w - logoW) / 2
                offsetY = (h - logoH) / 2
            }

            /*指定为UTF-8*/
            val hints = Hashtable<EncodeHintType, Any>()
            hints[EncodeHintType.CHARACTER_SET] = "utf-8"
            //容错级别
            hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
            //设置空白边距的宽度
            hints[EncodeHintType.MARGIN] = 0
            // 生成二维矩阵,编码时指定大小,不要生成了图片以后再进行缩放,这样会模糊导致识别失败
            var matrix: BitMatrix
            try {
                var mFormat : BarcodeFormat = BarcodeFormat.QR_CODE
                if (format == QRCodeAttr.QRTYPE.MAXI_CODE) {
                    mFormat = BarcodeFormat.DATA_MATRIX
                } else {
                    mFormat = BarcodeFormat.QR_CODE
                }
                matrix = MultiFormatWriter().encode(content, mFormat, w, h, hints)

                // 二维矩阵转为一维像素数组,也就是一直横着排了
                val pixels = IntArray(w * h)
                for (y in 0 until h) {
                    for (x in 0 until w) {
                        if (x >= offsetX && x < offsetX + logoW && y >= offsetY && y < offsetY + logoH) {
                            var pixel = logoBitmap!!.getPixel(x - offsetX, y - offsetY)
                            if (pixel == 0) {
                                if (matrix.get(x, y)) {
                                    pixel = -0x1000000
                                } else {
                                    pixel = -0x1
                                }
                            }
                            pixels[y * w + x] = pixel
                        } else {
                            if (matrix.get(x, y)) {
                                pixels[y * w + x] = -0x1000000
                            } else {
                                pixels[y * w + x] = -0x1
                            }
                        }
                    }
                }

                val bitmap = Bitmap.createBitmap(
                    w, h,
                    Bitmap.Config.ARGB_8888
                )
                bitmap.setPixels(pixels, 0, w, 0, 0, w, h)
                return bitmap


            } catch (e: WriterException) {

                print(e)
                return null
            }


        }


        fun createBRCode (s:String, w:Int, h:Int, show:Boolean, color:Int, size:Float) : Bitmap? {
            val barcodeFormat = BarcodeFormat.CODE_128
            if (!show)
                return encodeAsBitmap (s, barcodeFormat, w, h)

            var paint = Paint ()
            var rect = Rect ()
            var bitmap : Bitmap

            paint.textSize = size
            paint.getTextBounds (s, 0, s.length, rect)
            var b : Bitmap
            if (w >= rect.width()) {
                bitmap = BRCodeText (s, w, rect.height(), color, size)
                b = mixtureBitmap (encodeAsBitmap (s, barcodeFormat, w, h ), bitmap,  PointF(0.0f, h.toFloat()))!!
            } else {
                bitmap = BRCodeText (s, rect.width(), rect.height(), color, size)
                b = mixtureBitmap (encodeAsBitmap (s, barcodeFormat, rect.width(), h ), bitmap,  PointF(0.0f, h.toFloat()))!!
            }
            return b
        }


        private fun BRCodeText (s:String, w:Int, h:Int, color:Int, size:Float) : Bitmap {
            var paint : Paint = Paint ()
            paint.textSize = size
            paint.isAntiAlias = true
            paint.color = color
            paint.textAlign = Paint.Align.CENTER
            var bitmap : Bitmap = Bitmap.createBitmap (w, h + 20, Bitmap.Config.ARGB_8888)
            var canvas : Canvas = Canvas (bitmap)

            var fontMetrics : Paint.FontMetricsInt = paint.getFontMetricsInt ()
            var rect = Rect (0,0, w, h + 20)
            val baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2
            canvas.drawColor(Color.WHITE)
            canvas.drawText (s, rect.centerX ().toFloat(), baseline.toFloat(), paint)
            return bitmap
        }


        private fun encodeAsBitmap(
            contents: String,
            format: BarcodeFormat,
            desiredWidth: Int,
            desiredHeight: Int
        ): Bitmap {
            var result: BitMatrix? = null
            var fh = Code128Writer().encode(contents).size
            var sp = (desiredWidth.toFloat() / fh.toFloat()).toInt()
            fh = fh * sp.toInt()


            //配置条码参数
            //配置条码参数
            val hints: MutableMap<EncodeHintType, Any> = HashMap()
            //设置条码两边空白边距为0，默认为10，如果宽度不是条码自动生成宽度的倍数则MARGIN无效
            //设置条码两边空白边距为0，默认为10，如果宽度不是条码自动生成宽度的倍数则MARGIN无效
            hints[EncodeHintType.MARGIN] = 0

            try {

                result = MultiFormatWriter().encode(contents, format, fh, desiredHeight, hints)
            } catch (e: WriterException) {
                e.printStackTrace()
            }

            val width = result!!.width
            val height = result!!.height
            val pixels = IntArray(width * height)
            for (y in 0 until height) {
                for (x in 0 until width) {
                    pixels[y * width + x] = if (result.get(x, y)) -16777216 else -1
                }
            }
            val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
            return bitmap
        }


        private fun mixtureBitmap(first: Bitmap?, second: Bitmap?, fromPoint: PointF?): Bitmap? {
            if (first == null || second == null || fromPoint == null)
                return null
            val newBitmap =
                Bitmap.createBitmap(first.width, first.height + second.height, Bitmap.Config.ARGB_4444)
            val cv = Canvas(newBitmap)
            cv.drawBitmap(first, 0.0f, 0.0f, null)
            cv.drawBitmap(second, fromPoint.x, fromPoint.y, null)
            cv.save()
            cv.restore()
            return newBitmap
        }
    }


}